#include "Inf_FPM383.h"
#include "driver/uart.h"
#include "string.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// #include "esp_log.h"

// 接收缓冲区大小
static const int RX_BUF_SIZE = 1024;

// 接收数据, 默认成功 = 0, 所以默认 = 1
static uint8_t s_rece_data[100] = {1};

// 是否触发中断
volatile uint8_t is_has_finger = 0;
void Inf_FPM383_Handler_Back(void *arg)
{
    // MY_LOGE("是否触发中断  ");
    // ESP_EARLY_LOGI("是否触发中断  ");
    is_has_finger = 1;
}

/**
 * @brief 初始化
 *
 */
void Inf_FPM383_Init(void)
{
    // 配置usart
    uart_config_t uart_config = {
        // 设置UART的波特率（数据传输速率）
        .baud_rate = 57600,
        // 设置数据位长度（字长）
        .data_bits = UART_DATA_8_BITS,
        // 关闭校验
        .parity = UART_PARITY_DISABLE,
        // 设置停止位长度
        .stop_bits = UART_STOP_BITS_1,
        // 设置流控 关闭
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        // 时钟源默认
        .source_clk = UART_SCLK_DEFAULT,
    };
    // 添加配置
    uart_param_config(UART_NUM_1, &uart_config);
    // 设置引脚
    uart_set_pin(UART_NUM_1, TOUCH_TX, TOUCH_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    // 安装驱动
    uart_driver_install(UART_NUM_1, RX_BUF_SIZE, 0, 0, NULL, 0);

    // 配置外部中断
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_POSEDGE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1 << TOUCH_INT),
        .pull_down_en = 1,
        .pull_up_en = 0,
    };
    // 添加配置
    gpio_config(&io_conf);
    // 创建中断优先级
    // gpio_install_isr_service(0);
    // 关闭中断使能
    gpio_intr_enable(TOUCH_INT);
    // 添加中断回调函数
    gpio_isr_handler_add(TOUCH_INT, Inf_FPM383_Handler_Back, (void *)TOUCH_INT);
    // 关闭中断使能
    gpio_intr_disable(TOUCH_INT);
}

/**
 * @brie 进入睡眠模式
 *
 */
void Inf_FPM383_Sleep(void)
{
    // 发送指令
    uint8_t sendData_Array[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X33,                   // 指令码
        0X00, 0X37,             // 校验码
    };
    do
    {
        // 发送数据
        Com_Status status = Inf_FPM383_SendData(sendData_Array, 12);
        if (status == Com_OK)
        {
            MY_LOGE("发送成功");
        }
        // 接收数据
        status = Inf_FPM383_RecvData(12, 2000);
        if (status == Com_OK)
        {
            MY_LOGE("接收成功");
        }

        MY_LOGE("s_rece_data[9] %x", s_rece_data[9]);
        if (s_rece_data[9] == 0x00)
        {
            MY_LOGE("进入睡眠模式");

            // 打开中断使能
            gpio_intr_enable(TOUCH_INT);
            return;
        }
        vTaskDelay(1000);
    } while (s_rece_data[9] != 0X00);
}

/**
 * @brief 查询ID
 *
 * @param id
 * @return Com_Status
 */
uint16_t Inf_FPM383_FindId(void)
{
    // 1.封装指令包
    uint8_t cmd[13] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x04,             // 包长度
        0x1F,                   // 指令码
        0x00,                   // 页码
        '\0', '\0',             // 校验和
    };

    // 2.补充校验和
    Inf_FPM383_SetCheckSum(cmd, 13);

    // 发送指令
    Inf_FPM383_SendData(cmd, 13);
    // 接收应答包
    Inf_FPM383_RecvData(44, 2000);

    // 判断是不是接收成功,给一个默认值
    if (s_rece_data[9] != 0X00)
    {
        return 0;
    }

    // 遍历32位
    for (uint8_t i = 0; i < 32; i++)
    {
        // 从10 后迭代数据
        uint8_t byte = s_rece_data[10 + i];
        for (int j = 0; j < 8; j++)
        {
            // 判断是否有指纹
            if ((byte & 0x01) == 1)
            {
                // 右移
                byte >>= 1;
            }
            else
            {
                return i * 8 + j;
            }
        }
    }

    return 0;
}

/**
 * @brief 查询当前指纹ID
 *
 * @return uint16_t id
 */
int16_t Inf_FPM383_Current_Id(void)
{
    int16_t id = -1;
    uint8_t cmd[17] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x08,             // 包长度
        0x32,                   // 指令码
        0x03,                   // 分数等级
        0xFF, 0xFF,             // ID号:0xFFFF表示1:N搜索
        0x00, 0x07,             // 参数 灯光、预处理、不要求中间结果返回
        '\0', '\0',             // 校验和
    };
    // 2.补充校验和
    Inf_FPM383_SetCheckSum(cmd, 17);
    // 3.发送指令集
    Inf_FPM383_SendData(cmd, 17);
    // 4.接收应答包
    Inf_FPM383_RecvData(17, 1000);
    MY_LOGE("接收应答包 %x", s_rece_data[9]);
    if (s_rece_data[9] == 0x00)
    {
        id = s_rece_data[12];
    }

    return id;
}

/**
 * @brief 一站式录入指纹
 *
 * @param id
 * @return Com_Status
 */
Com_Status Inf_FPM383_RegFinger(uint16_t id)
{

    // 发送指令
    uint8_t sendData_Array[17] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备
        0X01,                   // 包标识
        0X00, 0X08,             // 包长度
        0X31,                   // 指令码
        '\0', '\0',             // 指纹ID
        0X01,                   // 录入次数
        0X00, 0X37,             // 参数
        '\0', '\0',             // 校验码
    };
    // 2.补充ID号
    sendData_Array[10] = (id >> 8);
    sendData_Array[11] = (id >> 0);

    Inf_FPM383_SetCheckSum(sendData_Array, 17);

    // 录入前必须取消操作
    Inf_FPM383_CancelOp();
    vTaskDelay(500);
    // Inf_FPM383_CancelOp();
    // vTaskDelay(500);
    // Inf_FPM383_CancelOp();
    // vTaskDelay(500);
    // Inf_FPM383_CancelOp();
    // vTaskDelay(500);

    // 3.发送指令集
    Inf_FPM383_SendData(sendData_Array, 17);
    // 4.接收应答包
    Inf_FPM383_RecvData(14, 1000);
    if (s_rece_data[9] != 0x00)
    {
        return Com_ERROR;
    }

    return Com_OK;
}

/**
 * @brief 发送数据
 *
 * @param data 数据指针
 * @param len 数据长度
 * @return Com_Status
 */
Com_Status Inf_FPM383_SendData(uint8_t *data, uint16_t len)
{
    // 发送数据
    int data_len = uart_write_bytes(UART_NUM_1, data, len);
    return (data_len == len) ? Com_OK : Com_ERROR;
}

/**
 * @brief 接收数据
 *
 * @param data 数据指针
 * @param len 数据长度
 * @param timeout 超时时间
 * @return Com_Status
 */
Com_Status Inf_FPM383_RecvData(uint32_t len, uint16_t timeout)
{
    memset(s_rece_data, 0, 100);
    // 接收数据
    int data_len = uart_read_bytes(UART_NUM_1, s_rece_data, len, timeout);
    return (data_len == len) ? Com_OK : Com_ERROR;
}

/**
 * @brief  设置校验位
 *
 * @param data 数据指针
 * @param len 数据长度
 */
void Inf_FPM383_SetCheckSum(uint8_t *data, uint16_t len)
{
    uint16_t sum = 0;
    // 校验位是 包标识 + 包长度 + 指令码 + 参数  = 校验数据
    for (uint16_t i = 6; i < len - 2; i++)
    {
        sum += data[i];
    }
    data[len - 2] = (sum >> 8); // 高字节
    data[len - 1] = sum & 0xFF; // 低字节
}

/**
 * @brief 删除当前指纹
 *
 * @param id 指纹id
 * @return Com_Status
 */
Com_Status Inf_FPM383_DelFinger(int16_t id)
{
    // 1.封装指令包
    uint8_t cmd[16] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x07,             // 包长度
        0x0C,                   // 指令码
        '\0', '\0',             // 页码(id)
        0x00, 0x01,             // 删除个数
        '\0', '\0',             // 校验和
    };
    cmd[10] = (id >> 8);
    cmd[11] = id & 0XFF;
    // 2.补充校验和
    Inf_FPM383_SendData(cmd, 16);
    // 5.接收应答包
    Inf_FPM383_RecvData(12, 1000);
    return (s_rece_data[9] == 0x00) ? Com_OK : Com_ERROR;
}

/**
 * @brief 验证指纹
 *
 * @return Com_Status
 */
Com_Status Inf_FPM383_CheckFinger(void)
{
    // 1.封装指令包
    uint8_t cmd[17] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x08,             // 包长度
        0x32,                   // 指令码
        0x03,                   // 分数等级
        0xFF, 0xFF,             // ID号:0xFFFF表示1:N搜索
        0x00, 0x07,             // 参数 灯光、预处理、不要求中间结果返回
        '\0', '\0',             // 校验和
    };

    // 2.补充校验和
    Inf_FPM383_SetCheckSum(cmd, 17);

    // 3.发送指令包
    Inf_FPM383_SendData(cmd, 17);

    // 4.直接获取最终的应答包
    Inf_FPM383_RecvData(17, 1000);

    // 5.判断是否搜索到指纹
    if (s_rece_data[9] == 0x00)
    {
        MY_LOGE("CheckID = %X", s_rece_data[12]);
        return Com_OK;
    }

    return Com_ERROR;
}

/**
 * @brief 读取设备信息
 *
 */
void Inf_FPM383_ReadId(void)
{
    // 1.封装指令包
    uint8_t cmd[13] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x04,             // 包长度
        0x34,                   // 指令码
        0x00,                   // 参数
        0x00, 0x39,             // 校验和
    };

    // 2.发送指令包
    Inf_FPM383_SendData(cmd, 13);

    // 3.接收应答包
    Inf_FPM383_RecvData(44, 2000);
    // 4.判断是否成功获取设备ID
    if (s_rece_data[9] == 0x00)
    {
        MY_LOGE("设备ID = %.32s\r\n", &s_rece_data[10]);
    }
    else
    {
        MY_LOGE("未获取到设备ID...\r\n");
    }
}

/**
 * @description:
 * @return {*}
 */
void Inf_FPM383_CancelOp(void)
{
    // 1.封装指令包
    uint8_t cmd[12] = {
        0xEF, 0x01,             // 包头
        0xFF, 0xFF, 0xFF, 0xFF, // 设备地址
        0x01,                   // 包标识
        0x00, 0x03,             // 包长度
        0x30,                   // 指令码
        '\0', '\0',             // 校验和
    };

    // 2.补充校验和
    Inf_FPM383_SetCheckSum(cmd, 12);

    do
    {
        // 3.发送指令集
        Inf_FPM383_SendData(cmd, 12);
        // 4.接收应答包
        Inf_FPM383_RecvData(12, 1000);
        vTaskDelay(1000);
    } while (s_rece_data[9] != 0x00);

    MY_LOGE("取消成功...\r\n");
}